分支限界法之最大团问题

A,最大团问题:给定一个无向图G=(V,E),其中V代表顶点集合,E代表边的集合。,如果U是V的子集,且对于U中任意两个顶点u和v都是相连的,即u-->v属于E,则称顶点子集U是图G的完全子图或者G的图。显然最大团就是指满足上述条件且含有顶点数最多的团。比如下图所示:
分支限界法之最大团问题

子集{A, B}是G 的大小为2 的团。这个团不是极大团(因为顶点数不是最多的),因为它包含在G 的更大团{A,B,E}中。{A, B, E}是G 的最大团。{A, D, E}和{B,C, E}也是G 的最大团。
B,分支限界法:该方法通常以广度优先或以最小耗费优先的方案搜索问题的解空间树。首先要弄明白什么是问题的解空间树。所谓解空间树就是问题的所有可能的解构成的树,因此问题的解一定在解空间树中。比如上面的图的解空间树如下图所示:
分支限界法之最大团问题

如上图所示,左边一列表示图G中的顶点,右边的树表示解空间树。每一层表示一个节点,树中的边1表示选择该节点,0表示不选择该节点。比如11001表示一个团,该团有3个顶点分别是1,2,5(从根节点出发对应上图);再比如01101表示一个含有3个顶点的团,它们分别是2,3,5。所以对于团问题,解空间树包含了所有团。求解最大团就是从解空间树种寻找顶点数最大的团。下面我们继续讨论分支限界法求解最大团问题。
当我们访问解空间树的一个顶点u时,假设cn表示u所在的团的顶点数,t表示顶点u在解空间树种的层次(比如上图1在层次为2,5层次为6),除此之外,每个顶点还有一个上界un表示最大团顶点数的上界,其中un=cn+n-t(n表示无向图中顶点总数)。在此优先队列式分枝限界算法中,un实际上也是优先队列(最大堆)中元素的优先级。算法总是从活结点优先队列中抽取具有最大un值的元素作为下一个扩展元素,因为un越大最后的找到的团顶点数可能就越多,这就是分支限界法中的限界思想。
C,算法思想:
1)首先假设解空间树已经生成了;
2)解空间树的根结点是初始扩展结点,对于这个特殊的扩展结点,其cn 值为0(表示当前团顶点数为0);
3)首先考察其左儿子结点。在左儿子结点处,将顶点u 加入到当前团中,并检查该顶点与当前团中其他顶
点之间是否有边相连。当顶点u与当前团中所有顶点之间都有边相连,则相应的左儿子结点是可行结点,将它加入到解空间树中并插入活结点优先队列,否则就不是可行结点;
4)接着继续考察当前扩展结点的右儿子结点。当un>bestn( bestn表示已经寻找到的团的顶点数,初始值为0)时,右子树中可能含有最优解,此时将右儿子结点加入到解空间树中并插入到活结点优先队列中;
5)继续上述3) 和 4)步骤直到搜索完整个解空间,算法结束;
6)搜索过程中通过上界un值来截枝避免访问不必要的节点。
下图为分支限界法解最大团问题的过程:

分支限界法之最大团问题
下面再补充一列,如下图所示:

分支限界法之最大团问题
下面来分析上图求解最大团中优先队列的变化情况:
1)从根节点0出发,将左子树1右子树2加入队列中并排序(根据un值排序,即图中节点的第二个数),队列为1,2;
2)1出队,将其左右子树3和4加入队列中并排序,队列为3,2,4;
3)3出队,其没有左子树不管,将右子树5加入队列并排序,队列为2,4,5;
4)2出队,将其左右子树6,7加入队列中并排序,队列为4,6,5,7(这里节点6和5的un值都为5为什么6排在5的前面呢,这时由于6在第二层,5在第三层,层次越低越排前面);
5)4出队,将其右子树8加入队列并排序,队列为6,5,7,8;
6)6出队,将其左右子树9,10加入队列并排序,队列为5,9,7,8,10(8,10没有孩子了,自然放在队列之后);
7)5出队,将其右子树加入队列并排序,队列为9,7,11,8,10(8和10依然排在最后);
8)9出队,将其右子树12加入对中并排序,队列为7,11,12,8,10;
9)7出队,将其右13,14加入对中并排序,队列为11,12,8,10,13,14(8,10,13,14均没有孩子了);
10)11出队,加入节点15,16,队列为12,8,10,13,15,14,16;
11)12出队,加入17,18,队列为8,10,13,14,15,17,16,18。此时队列中所有节点都没孩子节点了,然后依次出队算法结束。
这里的队列其实就是一个最大堆,我们知道在堆排序中,参照不同的属性(比如un的值)排序会有不同的堆序列,上面的分析是根据顶点的un值排序的堆,和图中稍有区别(因为上图可能还加入了其它参考值进行排序,因此对于un值相同的节点在队列中的顺序会有不同,我觉得这个无关紧要)。但是可以确定的是每次都是选择un值最大的节点出队(因为是大顶堆,其它元素un值不大于第一个)。



  • 46
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
最大团问题是指在一个无向图中找到一个最大的完全子图,其中任意两个节点都有边相连。采用分支限界法可以有效地解决最大团问题。 具体步骤如下: 1. 定义一个数据结构,记录当前搜索到的最大团大小、当前已选定的点集以及剩余可选点集。 2. 从剩余可选点集中选择一个点,将其加入当前已选定的点集中,并更新当前最大团大小。 3. 对于每个新加入的点,将其与已选定的点集中的所有点进行比较,找到与其相连的点,并将其从剩余可选点集中删除。 4. 递归搜索剩余可选点集中的点,重复执行步骤2和3,直到剩余可选点集为空。 5. 如果当前已选定的点集大小大于当前最大团大小,则更新最大团大小,并保存当前已选定点集。 6. 回溯到上一层,将已选择的点从当前已选定点集中删除,重新加入剩余可选点集中,继续搜索。 7. 最终得到的最大团即为所求。 以下是C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAXN 100 // 最大点数 int graph[MAXN][MAXN]; // 图的邻接矩阵 int n, max_clique; // 点数、最大团大小 bool is_clique[MAXN]; // 当前最大团包含的点集 void dfs(int cur_node, int cur_clique_size, int rest_nodes[], int rest_nodes_size) { if (rest_nodes_size == 0) { if (cur_clique_size > max_clique) { max_clique = cur_clique_size; for (int i = 0; i < n; i++) { is_clique[i] = false; } for (int i = 0; i < cur_clique_size; i++) { is_clique[rest_nodes[i]] = true; } } return; } if (cur_clique_size + rest_nodes_size <= max_clique) { // 剪枝 return; } int new_rest_nodes[MAXN], new_rest_nodes_size = 0; for (int i = 0; i < rest_nodes_size; i++) { int next_node = rest_nodes[i]; if (graph[cur_node][next_node]) { new_rest_nodes[new_rest_nodes_size++] = next_node; } } dfs(cur_node + 1, cur_clique_size, new_rest_nodes, new_rest_nodes_size); // 不选择当前节点 rest_nodes[cur_clique_size] = cur_node; dfs(cur_node + 1, cur_clique_size + 1, rest_nodes, cur_clique_size); // 选择当前节点 } int main() { scanf("%d", &n); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { scanf("%d", &graph[i][j]); } } int rest_nodes[MAXN], rest_nodes_size = n; for (int i = 0; i < n; i++) { rest_nodes[i] = i; } max_clique = 1; dfs(0, 0, rest_nodes, rest_nodes_size); printf("Max clique size: %d\n", max_clique); printf("Nodes in the clique: "); for (int i = 0; i < n; i++) { if (is_clique[i]) { printf("%d ", i); } } printf("\n"); return 0; } ``` 该算法的时间复杂度为O(2^n),因为在最坏情况下需要搜索整个指数级的状态空间。但是,由于采用了剪枝策略,实际运行效率要高于暴力枚举。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值